#include "Wincore.h"

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CWinApp
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CWinApp::CWinApp(void) : m_pMainWnd(NULL)
{
}

CWinApp::~CWinApp(void)
{
	if (NULL != m_pMainWnd)
	{

		m_pMainWnd->DestroyWindow();
		delete m_pMainWnd;
	}
}

void CWinApp::Run()
{
	MSG Msg;

	if (InitInstance())
	{
		while (GetMessage(&Msg, NULL, 0, 0))
		{
			TranslateMessage(&Msg);
			DispatchMessage(&Msg);
		}
	}

	ExitInstance();

	return;
}

bool CWinApp::InitInstance()
{
	return false;
}

void CWinApp::ExitInstance()
{
	return;
}


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CWinWnd
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CWinWnd::CWinWnd(void) : m_hWnd(NULL)
{
	m_hInstance = GetModuleHandle(NULL);
}

CWinWnd::~CWinWnd(void)
{

}

void CWinWnd::ShowWindow(int nShowCmd)
{
	if (NULL != m_hWnd && IsWindow(m_hWnd))
	{
		::ShowWindow(m_hWnd, nShowCmd);
	}

	return;
}

void CWinWnd::CenterWindow()
{	
	assert(NULL != m_hWnd && IsWindow(m_hWnd));
	
	HWND hParent = GetParent(m_hWnd);

	if (NULL == hParent || !IsWindow(m_hWnd))
	{
		hParent = GetDesktopWindow();
	}

	if (NULL != m_hWnd && IsWindow(m_hWnd))
	{
		RECT rtWnd;
		RECT rtParent;
		GetWindowRect(m_hWnd, &rtWnd);
		GetWindowRect(hParent, &rtParent);
	
		int nW	= rtWnd.right - rtWnd.left;
		int nH	= rtWnd.bottom - rtWnd.top;

		int nX	= rtParent.left + (((rtParent.right - rtParent.left) - nW) >> 1);
		int nY	= rtParent.top + (((rtParent.bottom - rtParent.top) - nH) >> 1);

		SetWindowPos(m_hWnd, NULL, nX, nY, nW, nH, SWP_NOACTIVATE|SWP_NOSIZE);
	}

	return;
}

void CWinWnd::DestroyWindow()
{
	if (NULL != m_hWnd && IsWindow(m_hWnd))
	{
		::DestroyWindow(m_hWnd);
		m_hWnd = NULL;
	}
}

bool CWinWnd::IsValid()
{
	return (NULL != m_hWnd && IsWindow(m_hWnd));
}

HWND CWinWnd::Create(const TCHAR* szWndName, DWORD dwStyle, int x, int y, int cx, int cy, HWND hParent)
{
	if (NULL != GetClassName() && _RegisterWindowClass())
	{
		m_hWnd = ::CreateWindow(GetClassName(), szWndName, dwStyle, x, y, cx, cy, hParent, NULL, m_hInstance, this);
	}

	return m_hWnd;
}

LRESULT CWinWnd::FinalWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
	return ::DefWindowProc(hWnd, nMsg, wParam, lParam);
}

DWORD CWinWnd::GetClassStyle() const
{
	return CS_VREDRAW|CS_HREDRAW;
}

const TCHAR* CWinWnd::GetClassName() const
{
	return _T("SmartWin32++");
}

bool CWinWnd::_RegisterWindowClass()
{
	bool bRes = false;
	
	WNDCLASS WndClass;
	if (GetClassInfo(m_hInstance, GetClassName(), &WndClass))
	{
		bRes = true;
	} else {
		WndClass.style			= GetClassStyle();
		WndClass.lpfnWndProc	= (WNDPROC)_WndProc;
		WndClass.lpszClassName	= GetClassName();
		WndClass.hInstance		= m_hInstance;
		WndClass.hbrBackground	= static_cast<HBRUSH>(GetStockObject(WHITE_BRUSH));
		WndClass.hCursor		= static_cast<HCURSOR>(LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW)));
		WndClass.hIcon			= static_cast<HICON>(LoadIcon(NULL, MAKEINTRESOURCE(IDI_APPLICATION)));
		WndClass.cbClsExtra		= 0;
		WndClass.cbWndExtra		= 0;
		WndClass.lpszMenuName	= NULL;
		bRes = (0 != RegisterClass(&WndClass));	
	}
	assert(bRes);
	return bRes;
}

LRESULT CALLBACK CWinWnd::_WndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
	CWinWnd* pThis = NULL;

	if (WM_NCCREATE == nMsg)
	{		
		CWinWnd* pThis = static_cast<CWinWnd*>(reinterpret_cast<LPCREATESTRUCT>(lParam)->lpCreateParams);
		assert(NULL != pThis);
		if (NULL != pThis)
		{
			pThis->m_hWnd = hWnd;
			SetWindowLongPtr(pThis->m_hWnd, GWLP_USERDATA, reinterpret_cast<LPARAM>(pThis));
		}
	} else {
		pThis = reinterpret_cast<CWinWnd*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
 		if(WM_NCDESTROY == nMsg && pThis != NULL) 
		{
 			::SetWindowLongPtr(pThis->m_hWnd, GWLP_USERDATA, 0L);
 			pThis->m_hWnd = NULL;
		}
	}
	
	if (NULL != pThis)
	{
		return pThis->WndProc(hWnd, nMsg, wParam, lParam);
	}

	return ::DefWindowProc(hWnd, nMsg, wParam, lParam);
}